\section{Compiling P4 to eBPF}\label{sec:compilation}

In this section we describe two open-source compilers that translate
P4 programs in stylized C programs, that can in turn be compiled into
eBPF programs using the LLVM eBPF back-end.

\subsection{Packet filters with eBPF}\label{sec:ebpf}

The eBPF back-end is part of the P4 reference compiler
implementation~\cite{p4-ebpf-backend}.  This back-end targets a
relatively simple packet filter architecture.
Figure~\ref{fig:ebpf-model} shows the architectural model of an eBPF
packet filter expressed in P4.  This architecture comprises a parser
and a control block; the control block must produce a Boolean value
which indicates whether the packet is accepted or not.

\begin{figure}[h]
\begin{lstlisting}
#include <core.p4>

extern CounterArray {
    CounterArray(bit<32> max_index, bool sparse);
    void increment(in bit<32> index);
}

extern array_table {
    array_table(bit<32> size);
}

extern hash_table {
    hash_table(bit<32> size);
}

parser parse<H>(packet_in packet, out H headers);
control filter<H>(in H headers, out bool accept);

package ebpfFilter<H>(parse<H> prs,
                      filter<H> filt);
\end{lstlisting}
\caption{Packet filter P4 architectural model for an eBPF
  target.}\label{fig:ebpf-model}
\end{figure}

Figure~\ref{fig:count} shows a P4 program written for this
architecture that counts the number of IPv4 packets that are
encountered.

\begin{figure}
\begin{lstlisting}
#include <core.p4>
#include <ebpf_model.p4>

typedef bit<48> EthernetAddress;
typedef bit<32> IPv4Address;

header Ethernet {
   EthernetAddress dstAddr;
   EthernetAddress srcAddr;
   bit<16> etherType;
}

// IPv4 header without options
header IPv4 {
   bit<4>       version;
   bit<4>       ihl;
   bit<8>       diffserv;
   bit<16>      totalLen;
   bit<16>      identification;
   bit<3>       flags;
   bit<13>      fragOffset;
   bit<8>       ttl;
   bit<8>       protocol;
   bit<16>      hdrChecksum;
   IPv4Address  srcAddr;
   IPv4Address  dstAddr;
}

struct Headers {
   Ethernet eth;
   IPv4     ipv4;
}

parser prs(packet_in p, out Headers headers) {
   state start {
      p.extract(headers.eth);
      transition select(headers.eth.etherType) {
         0x800 : ip;
         default : reject;
      }
   }

   state ip {
      p.extract(headers.ipv4);
      transition accept;
   }
}

control pipe(in Headers headers, out bool pass){
   CounterArray(32w10, true) ctr;

   apply {
      if (headers.ipv4.isValid()) {
         ctr.increment(headers.ipv4.dstAddr);
         pass = true;
      } else
         pass = false;
   }
}

// Instantiate main package
ebpfFilter(prs(), pipe()) main;
\end{lstlisting}
\caption{A P4 program that counts the number of IPv4 packets
  encountered.}\label{fig:count}
\end{figure}

Compilation to C is fairly straightforward; the generated C program is
always memory-safe, using bounds-checks for all packet accesses.  For
the entire P4 program a single C function is generated which returns a
Boolean value.  Table~\ref{table:translation} shows how each P4
construct is converted to a C construct.  Currently programs with
parser loops are rejected, but a parser loop unrolling pass (under
development) will allow such programs to be compiled.

\begin{table}[h]
  \footnotesize
  \begin{tabular}{|l|p{4.8cm}|} \hline
    \textbf{P4 construct} & \textbf{C Translation} \\ \hline \hline
    \texttt{header} & \texttt{struct} with an additional \texttt{valid} bit \\ \hline
    \texttt{struct} & \texttt{struct} \\ \hline
    parser state    & block statement \\ \hline
    state transition & \texttt{goto} statement \\ \hline
    \texttt{extract} call & load/shift/mask data from packet \\ \hline
    table & 2 eBPF maps --- one for actions, one for the default action \\ \hline
    table key type & \texttt{struct} type \\ \hline
    \texttt{action} & tagged \texttt{union} with action parameters \\ \hline
    \texttt{action} parameters & \texttt{struct} \\ \hline
    \texttt{action} body & block statement \\ \hline
    table \texttt{apply} & lookup in eBFP map + \texttt{switch} statement with all actions \\ \hline
    counters & eBPF map \\ \hline
  \end{tabular}
  \caption{Compiling P4 constructs to C.}\label{table:translation}
\end{table}

\subsection{Packet forwarding with XDP}\label{sec:xdp}


A second P4 to C compiler, P4C-XDP, is available as an open-source
project hosted at~\cite{p4-xdp-backend}. P4C-XDP is licensed under the GNU 
GPL and Apache License.
This compiler extends the eBPF compiler from Section~\ref{sec:ebpf}. It can 
target either a packet filter, or a packet switch.  The following listing shows 
the XDP architectural model targeted by this compiler. You can see that a
P4 XDP program can (1) return to the kernel one of the four outcomes
described in Section~\ref{sec:xdp-background}, and (2) it can also
modify the packet itself, by inserting, modifying or deleting headers.

\begin{figure}
\begin{lstlisting}
#include <ebpf_model.p4>
enum xdp_action {
  XDP_ABORTED,
  XDP_DROP,
  XDP_PASS,
  XDP_TX
}
struct xdp_input { bit<32> input_port }

struct xdp_output {
  xdp_action output_action;
  bit<32> output_port;
}

parser xdp_parse<H>(packet_in packet,
                    out H headers);
control xdp_switch<H>(inout H hdrs,
                      in xdp_input i,
                      out xdp_output o);
control xdp_deparse<H>(in H headers,
                       packet_out packet);

package xdp<H>(xdp_parse<H> p,
               xdp_switch<H> s,
               xdp_deparse<H> d);
\end{lstlisting}
\caption{XDP packet switching architectural
  model.}\label{fig:xdp-model}
\end{figure}
